#ifndef __OBJECT_POOL_ALLOC_HPP__
#define __OBJECT_POOL_ALLOC_HPP__

#include "mutex.hpp"
#include "lock.hpp"
#include <deque>
#include <stdexcept>

namespace vpm
{
	namespace utils
	{

		template<typename _Tp>
		class ObjectPoolAllocator
		{	
			enum 
			{
				POOL_INIT_SIZE      = 1000, 
				POOL_INCREASE_SIZE  = 100, //

			};
		public:
			typedef size_t     size_type;
			typedef ptrdiff_t  difference_type;
			typedef _Tp*       pointer;
			typedef const _Tp* const_pointer;
			typedef _Tp&       reference;
			typedef const _Tp& const_reference;
			typedef _Tp        value_type;

			template<typename _Tp1>
			struct rebind
			{ 
				typedef ObjectPoolAllocator<_Tp1> other; 
			};

			ObjectPoolAllocator() throw() 
			{
				m_totalSize =0; 
				m_readSize =0;
				m_writeSize =0; 
				Lock lock(m_readMutex); 
				inflate();
			}

			~ObjectPoolAllocator() throw() 
			{
				for(typename std::deque<pointer>::iterator itr = m_readObjects.begin(); itr != m_readObjects.end(); ++itr)
				{
					::operator delete (*itr);
				}
				for(typename std::deque<pointer>::iterator itr = m_writeObjects.begin(); itr != m_writeObjects.end(); ++itr)
				{
					::operator delete (*itr);
				}
				this->m_readObjects.clear();
				this->m_writeObjects.clear();
				printf("Total Allocate size %d, Read Size %d, Write Size %d",m_totalSize ,m_readSize, m_writeSize);
			}

			pointer address(reference __x) const { return &__x; }

			const_pointer address(const_reference __x) const { return &__x; }

			// NB: __n is permitted to be 0.  The C++ standard says nothing
			// about what the return value is when __n == 0.
			_Tp* allocate(size_type __n= sizeof(value_type), const void* = 0)
			{
				_Tp* __ret = 0;
				if (__n)
				{
					if (__n <= this->max_size())
					{
						//__ret = static_cast<_Tp*>(_Alloc::allocate(__n * sizeof(_Tp)));
						Lock lock(m_readMutex); 
						if (m_readObjects.empty())
						{
							this->inflate();
						}

						__ret = m_readObjects.front();
						m_readObjects.pop_front();
						m_readSize ++;
						return __ret;
					}
					else
						throw std::bad_alloc(); 

				}

				return __ret;
			}

			// __p is not permitted to be a null pointer.
			void deallocate(pointer __p, size_type __n= sizeof(value_type))
			{ 
				//_Alloc::deallocate(__p, __n * sizeof(_Tp)); 
				Lock lock(m_writeMutex); 
				m_writeObjects.push_back(__p);
				m_writeSize  ++; 
			}

			size_type max_size() const throw() 
			{ 
				return size_t(-1) / sizeof(_Tp); 
			}

			void construct(pointer __p, const _Tp& __val) 
			{ 
				new(__p) _Tp(__val); 
			}
			void destroy(pointer __p) 
			{ 
				__p->~_Tp(); 
			}

		private:
			void inflate(int count = POOL_INCREASE_SIZE)
			{
				Lock lock(m_writeMutex);
				if (m_writeObjects.empty())
				{
					for (int i = 0; i < count ;i++)
					{
						pointer  _p = static_cast<pointer>(::operator new (sizeof(value_type)));
						m_readObjects.push_back(_p);
					}
					m_totalSize += count;
				}
				else 
				{
					printf("do swap with read and write queue");
					m_readObjects.swap(m_writeObjects);
				}
			}

			ObjectPoolAllocator(const ObjectPoolAllocator&) throw() 
			{

			}

			// not allow copy 
			template<typename _Tp1>
			ObjectPoolAllocator(const ObjectPoolAllocator<_Tp1>&) throw() 
			{

			}

			template<typename _Tp1>
			void operator = (const ObjectPoolAllocator<_Tp1>&) throw() 
			{

			}

			std::deque<pointer> m_readObjects;
			std::deque<pointer> m_writeObjects;
			Mutex m_readMutex; 
			Mutex m_writeMutex; 

			int m_readSize ;
			int m_writeSize; 
			int m_totalSize ;
		};

	}
}



#endif //
  
  
